using System.Text.Json.Serialization;

namespace LightCAD.Core.Elements
{
    public class Line : Element
    {
        [JsonInclude,JsonPropertyName("S")]
        [JsonConverter(typeof(Vector2dConverter))]
        public Vector2d Start;
        [JsonInclude, JsonPropertyName("E")]
        [JsonConverter(typeof(Vector2dConverter))]
        public Vector2d End;

        public Line()
        {
            this.Type = ElementType.Line;
        }
        public Line(Vector2d start, Vector2d end) : this()
        {
            this.Start = start;
            this.End = end;
        }
        public Line(double startX, double startY, double endX, double endY) : this()
        {
            this.Start.X = startX;
            this.Start.Y = startY;
            this.End.X = endX;
            this.End.Y = endY;
        }

        public override Element Clone()
        {
            var clone = new Line();
            clone.Copy(this);
            clone.Initilize(this.Document);
            return clone;

        }

        public override void Copy(Element src)
        {
            base.Copy(src);
            var line = ((Line)src);
            this.Start = line.Start;
            this.End = line.End;
        }

        public void Set(Vector2d? start = null, Vector2d? end = null, bool fireChangedEvent = true)
        {
            //PropertySetter:Start,End
            if (!fireChangedEvent)
            {
                if (start != null) this.Start = start.Value;
                if (end != null) this.End = end.Value;
            }
            else
            {
                bool chg_start = (start != null && start != this.Start);
                if (chg_start)
                {
                    PropertyChangedBefore(nameof(Start), this.Start, start);
                    var oldValue = this.Start;
                    this.Start = start.Value;
                    PropertyChangedAfter(nameof(Start), oldValue, this.Start);
                }
                bool chg_end = (end != null && end != this.End);
                if (chg_end)
                {
                    PropertyChangedBefore(nameof(End), this.End, end);
                    var oldValue = this.End;
                    this.End = end.Value;
                    PropertyChangedAfter(nameof(End), oldValue, this.End);
                }
            }
        }
        public override Box2d GetBoundingBox()
        {
            return new Box2d(this.Start, this.End);
        }
        public override bool IntersectWithBox(Box2d testBox)
        {
            var thisBox = this.BoundingBox;
            if (!thisBox.IntersectWith(testBox))
            {
                return false;
            }


            if (testBox.Contains(this.Start) || testBox.Contains(this.End))
            {
                return true;
            }

            var pkPnt1 = new Vector2d(testBox.Location.X, testBox.Location.Y);
            var pkPnt2 = new Vector2d(testBox.Location.X, testBox.Location.Y + testBox.Height);
            var pkPnt3 = new Vector2d(testBox.Location.X + testBox.Width, testBox.Location.Y + testBox.Height);
            var pkPnt4 = new Vector2d(testBox.Location.X + testBox.Width, testBox.Location.Y);

            double d1 = Vector2d.Cross(this.Start - pkPnt1, this.End - pkPnt1);
            double d2 = Vector2d.Cross(this.Start - pkPnt2, this.End - pkPnt2);
            double d3 = Vector2d.Cross(this.Start - pkPnt3, this.End - pkPnt3);
            double d4 = Vector2d.Cross(this.Start - pkPnt4, this.End - pkPnt4);

            if (d1 * d2 <= 0 || d1 * d3 <= 0 || d1 * d4 <= 0)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        public override bool IncludeByBox(Box2d testBox)
        {
            var thisBox = this.BoundingBox;
            if (!thisBox.IntersectWith(testBox))
            {
                return false;
            }
            return (testBox.Contains(this.Start) && testBox.Contains(this.End));
        }

        public override void Translate(double dx, double dy)
        {
            var ts = new Vector2d(this.Start.X + dx, this.Start.Y + dy);
            var te = new Vector2d(this.End.X + dx, this.End.Y + dy);
            Set(ts, te);
            ResetBoundingBox();
        }
    }
}